﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tycho.Runtime;

namespace Tycho.Transactions {
    public class TransactionLog {
        public class LocalObject {
            public LocalObject (object obj, long vers) {
                Object = obj;
                Version = vers;
            }

            public object Object;
            public long Version;
            public bool Modified;
        }

        internal Dictionary<ITransactionalObject, LocalObject> Objects { get; private set; }

        public TransactionLog () {
            Objects = new Dictionary<ITransactionalObject, LocalObject> (new ReferenceEqualityComparer<ITransactionalObject> ());
        }

        protected virtual LocalObject GetObjectFromLive (ITransactionalObject liveObject) {
            lock (liveObject) {
                return liveObject.CreateTransactionLocalObject ();
            }
        }

        public LocalObject GetLocalObject (ITransactionalObject liveObject, bool toModify) {
            LocalObject localObject;

            if (!Objects.TryGetValue (liveObject, out localObject)) {
                localObject = Objects [liveObject] = GetObjectFromLive (liveObject);
            }

            localObject.Modified |= toModify;
            return localObject;
        }

        public object GetObject (ITransactionalObject liveObject, bool toModify) {
            return GetLocalObject (liveObject, toModify).Object;
        }

        public void Merge (TransactionLog log) {
            foreach (KeyValuePair<ITransactionalObject, LocalObject> entry in log.Objects) {
                Objects [entry.Key] = entry.Value;
            }
        }
    }

    public class ReferenceEqualityComparer<T> : IEqualityComparer<T> {
        public bool Equals (T x, T y) {
            return Object.ReferenceEquals (x, y);
        }

        public int GetHashCode (T obj) {
            return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode (obj);
        }
    }
}
